package com.anasoft.os.s4j.util;

import java.lang.annotation.Annotation;

/**
 * Used to scan classes for annotations.
 * 
 * @author vojtech.szocs
 */
public final class AnnotationFinder {

    private AnnotationFinder() { throw new AssertionError(); }
    
    /**
     * Attempts to find an annotation of type <tt>annotationClass</tt>
     * on the given <tt>targetClass</tt>.
     * <p>
     * This method works by scanning target class annotations and their
     * "child" annotations recursively. The Java core annotation package
     * is excluded from scanning to avoid infinite recursion and consequent
     * stack overflow errors.
     * 
     * @param targetClass Class on which to start scanning.
     * @param annotationClass Requested annotation type.
     * @return Annotation of the given type or <tt>null</tt> if not found.
     */
    public static <A extends Annotation> A find(Class<?> targetClass, Class<A> annotationClass) {
        A found = null;
        
        for (Annotation annotation : targetClass.getAnnotations()) {
            if (annotation.annotationType().equals(annotationClass))
                return annotationClass.cast(annotation);
            
            found = find(annotation, annotationClass);
            
            if (found != null)
                break;
        }
        
        return found;
    }
    
    private static <A extends Annotation> A find(Annotation targetAnnotation, Class<A> annotationClass) {
        A found = null;
        
        for (Annotation annotation : targetAnnotation.annotationType().getAnnotations()) {
            // skip annotations from the core annotation package to avoid infinite recursion
            if (annotation.annotationType().getPackage().equals(Annotation.class.getPackage()))
                continue;
            
            if (annotation.annotationType().equals(annotationClass))
                return annotationClass.cast(annotation);
            
            found = find(annotation, annotationClass);
            
            if (found != null)
                break;
        }
        
        return found;
    }
    
}
